<?php

set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__);
class XForms {
  public $xlist = array();
  public $document;
  public $output;
  public $script='';
  public $fileName;
  public $currentXml=null;
  protected $xdocument;
  function load($fileName,$xml=null){
    $this->fileName=$fileName;
    $this->output = new DOMDocument();
    $this->document = new DOMDocument();
    if(!isset($xml)) $this->document->load($fileName);
    else {
    echo $xml;die;
      $this->document->loadXML($xml);
    }
    return $this->xdocument = $this->factory($this->getFirstElement($this->document), $this);
  }
  function render(){
    //PROCESA EL CONTENIDO
    $res = $this->xdocument->render2();
    //GENERA EL CODIGO HTML
    $html = '<!DOCTYPE html>' . "\n";
    $this->output->appendChild($res[0]);
    $html .= str_replace('></link>', '/>', $this->output->saveHTML());
    return str_replace('/**@script**/',$this->script, $html);
  }
  function factory($node){
    @list($ns, $nn) = explode(":", $node->nodeName);
    if(!isset($nn)) {$nn=$ns;$ns = 'xhtml';}
    $nn = preg_replace('/[^a-z0-9]/i', '_', $nn);
    if($node instanceof DOMElement) {
      if($node->namespaceURI=="http://www.w3.org/2002/xforms") $ns = 'xforms';
      if($node->namespaceURI=="http://orbeon.org/oxf/xml/form-runner") $ns = 'frorbeon';
      if($node->namespaceURI=="http://www.w3.org/1999/xhtml") $ns = 'xhtml';
    }
    $dir = strtolower($ns);
    $file = strtoupper(substr($nn,0,1)) . strtolower(substr($nn,1)) . '.php';
    $class = $ns . "_" . $nn;
    if(!class_exists($class)) {
      if(file_exists(__DIR__.'/'.$dir . "/" . $file)) {
        include_once($dir . "/" . $file);
      }
    }
    //if($class=="xhtml__text") var_dump($class,class_exists($class));
    if(class_exists($class)) {
      $obj = new $class($node, $this);
    } elseif($node instanceof DOMElement) {
      if($node->namespaceURI=="http://www.w3.org/2002/xforms") {
        require_once('xforms/Core.php');
        $obj = new XForms_Core($node, $this);
      } elseif($node->namespaceURI=="http://orbeon.org/oxf/xml/form-runner") {
        require_once('frorbeon/Core.php');
        $obj = new FrOrbeon_Core($node, $this);
      } else {
        require_once('Node.php');
        $obj = new Node($node, $this);
      }
    } else {
      require_once('Node.php');
      $obj = new Node($node, $this);
    }
    //if($class=="xhtml__text") var_dump(get_class($obj));
    //$this->append($obj);
    return $obj;
  }
  function getXPath($node){
    if($node->parentNode==null) return "";//"/".$node->nodeName;
    $path = $this->getXPath($node->parentNode);
    $i=0;$l=0;
    foreach($node->parentNode->childNodes as $ch) {
      if($ch->nodeName===$node->nodeName) $l++;
      if($ch===$node) $i = $l;
    }
    if($l>1) $path.= "/".$node->nodeName."[$i]";
    else $path.= "/".$node->nodeName;
    return $path;
  }
  function append($xelement) {
    $this->xlist[$xelement->getXPath()]=$xelement;
  }
  function xmlToPhp($node){
    if($node instanceof DOMElement) {
      $res=new StdClass();
      $res->_nodeName = $node->nodeName;
      $res->_childNodes = array();
      foreach($node->attributes as $ch) {
        $name = $ch->nodeName;
        $res->$name = $ch->nodeValue;
      }
      foreach($node->childNodes as $ch) {
        $re = $this->xmlToPhp($ch);
        if(!is_string($re) || trim($re)!='') $res->_childNodes[] = $re;
      }
    } else {
      $res = $node->nodeValue;
    }
    return $res;
  }
  function getElementById($id, $ctx=null){
    if(!isset($ctx)) {
      $e = $this->document->getElementById($id);
      if($e) {
        return $e;
      } else {
        return $this->getElementById($id, $this->document->childNodes->item(0));
      }
    } else {
      if($ctx->hasChildNodes()) {
        foreach($ctx->childNodes as $ch) if($ch instanceof DOMElement) {
          if($ch->getAttribute("id")==$id) {
            return $ch;
          } else {
            $res = $this->getElementById($id, $ch);
            if($res) return $res;
          }
        }
      }
      return null;
    }
  }
  function findBindings($exp, $ctx){
    require_once("xpath/Core.php");
    $xpath = new DOMXPath($this->document);
    $xpath->registerNamespace("php", "http://php.net/xpath");
    $xpath->registerNamespace("xforms", "http://www.w3.org/2002/xforms");
    $xpath->registerNamespace("frorbeon", "http://orbeon.org/oxf/xml/form-runner");
    $xpath->registerNamespace("xhtml", "http://www.w3.org/1999/xhtml");
    $GLOBALS["currentXP"] = $this;
    $exp = $this->registerXPathFunctions($xpath, $exp);
    $exp = preg_replace('/\$([\w\d-]+)/', 'php:function("xpath_resource","fr-$1")', $exp);
    if($ctx) $refs = $xpath->query($exp, $ctx);
    else $refs = $xpath->query($exp);
    //if($refs->length>0) {
      return $refs;
    //}
    //return null;
  }
  function findBinding($exp, $ctx, $nodesetIndex=0){
    $refs = $this->findBindings($exp, $ctx);
    if($refs->length>0) {
      return $refs->item($nodesetIndex);
    }
    return $refs;
  }
  function registerXPathFunctions($xpath, $exp){
    $fns = get_defined_functions();
    foreach($fns["user"] as $fn){
      if(substr($fn,0,6)=="xpath_") {
        $f = substr($fn,6);
        $xpath->registerPHPFunctions($fn);
        //preg_replace('/\b'.$f.'\(\)/')
        $exp=str_replace("$f()","php:function('$fn')",$exp);
        $exp=str_replace("$f(","php:function('$fn',",$exp);
      }
    }
    return $exp;
  }
  function findXElement($node){
    //echo $this->getXPath($node);
    //dump($node);
    //print_r(array_keys($this->xlist));
    $xpath = $this->getXPath($node);
    return isset($this->xlist[$xpath]) ? $this->xlist[$xpath] : null;
  }
  function findXElementById($id){
    return $this->xlist[$this->getXPath($this->document->getElementById($id))];
  }
  function findXParentElement($node, $class){
    while($node->parentNode) {
      $x = $this->findXElement($node->parentNode);
      if(isset($x)) {
      //var_dump(get_class($x));
        eval('$b=$x instanceof ' . "$class;");
        if($b) {
          return $x;
        }
      }
      $node = $node->parentNode;
    }
    return null;
  }
  function getDefaultModel(){
    return $this->document->getElementsByTagName("model")->item(0);
  }
  function getDefaultInstance($model){
    return $model->getElementsByTagName("instance")->item(0);
  }
  function getFirstElement($node){
    foreach($node->childNodes as $n) {
      if($n instanceof DOMElement){
        return $n;
      }
    }
    return null;
  }
  //7.2 Evaluation Context
  function getOutermostBindingElement($node){
    //TODO: Detectar Binding Element
    if($node->parentNode->nodeName=="model") {
      return $node;
    } elseif($node->parentNode->nodeName=="#document") {
      return $node;
    } else {
      return $this->getOutermostBindingElement($node->parentNode);
    }
  }
  /*function __sleep(){
    $this->currentXml=$this->document->saveXML();
    return array("fileName","currentXml");
  }
  function __wakeup(){
    if($this->fileName) $this->load($this->fileName, $this->currentXml);
  }*/
}
